2.2 Dart compile Dart 部分实现
由《1.1 Dart 命令——Dart SDK 的入口》的架构组成可知,dart 命令由 C++ 和 Dart 两部分组成。Dart 部分主要处理命令行参数解析转换,之后以创建新进程的方式,调用 dart 命令的 C++ 实现部分。在本文中主要分析 Dart 侧的实现。
dart compile
的实现位于 pkg/dartdev/lib/src/commands/compile.dart
。核心的类是 CompileCommand
,内部根据不同的编译类型,细分为多个子指令。
如何调试 Dart 命令
既然 dart 命令是使用 Dart 开发的,可以很方便地进行调试,使用 dart run
dartdev
的入口即可:
[maxiee@archlinux maxiee_learn]$ /home/maxiee/Code/dart-sdk/sdk/out/ReleaseX64/dart-sdk/bin/dart run /home/maxiee/Code/dart-sdk/sdk/pkg/dartdev/bin/dartdev.dart compile jit-snapshot main.dart
需要注意的是,我们应当使用与 Dart SDK 源码匹配的 Dart 版本来运行。或者向我上面命令这样,我先从源码编译了 Dart SDK,然后用编译出来的 dart
来运行它自己的源码。
CompileSnapshotCommand
JIT snapshot、AOT snapshot、Kernal 编译均由 CompileSnapshotCommand 命令负责。run 方法为功能实现:
@override
FutureOr<int> run() async {
final args = argResults!;
// ...
// 源码路径
final String sourcePath = args.rest[0];
// ...
// Determine output file name.
// 如果用户指定输出文件名,则直接使用
// 如果未指定,以源码文件名加对应模式下的后缀自动生成
// 后缀:kernel-dill, JIT-jit, AOT-aot
String? outputFile = args[outputFileOption.flag];
if (outputFile == null) {
final inputWithoutDart = sourcePath.endsWith('.dart')
? sourcePath.substring(0, sourcePath.length - 5)
: sourcePath;
outputFile = '$inputWithoutDart.$fileExt';
}
// 启用的实验功能
// 获取 define 环境变量
final enabledExperiments = args.enabledExperiments;
final environmentVars = args['define'] ?? <String, String>{};
// Build arguments.
// 生成构建参数
final buildArgs = <String>[];
// 编译类型
buildArgs.add('--snapshot-kind=$formatName');
// 输出文件
buildArgs.add('--snapshot=${path.canonicalize(outputFile)}');
// 是否开启健全空安全
final bool soundNullSafety = args['sound-null-safety'];
if (!soundNullSafety) {
if (!shouldAllowNoSoundNullSafety()) {
return compileErrorExitCode;
}
// 非健全空安全
buildArgs.add('--no-sound-null-safety');
}
// packagesOption
final String? packages = args[packagesOption.flag];
if (packages != null) {
buildArgs.add('--packages=$packages');
}
// 日志等级
final String? verbosity = args[verbosityOption.flag];
buildArgs.add('--verbosity=$verbosity');
if (enabledExperiments.isNotEmpty) {
buildArgs.add("--enable-experiment=${enabledExperiments.join(',')}");
}
if (verbose) { // 唠叨
buildArgs.add('-v');
}
if (environmentVars.isNotEmpty) {
buildArgs.addAll(environmentVars.map<String>((e) => '--define=$e'));
}
buildArgs.add(path.canonicalize(sourcePath));
// Add the training arguments.
if (args.rest.length > 1) {
buildArgs.addAll(args.rest.sublist(1));
}
log.stdout('Compiling $sourcePath to $commandName file $outputFile.');
// TODO(bkonyi): perform compilation in same process.
// 启动 dart 进程
final process = await startDartProcess(sdk, buildArgs);
routeToStdout(process);
return process.exitCode;
}
dartdev
中的 dart 并不负责具体编译,具体编译由 startDartProcess
调用实际的编译命令进行:
/// A utility method to start a Dart VM instance with the given arguments and an
/// optional current working directory.
///
/// [arguments] should contain the snapshot path.
Future<Process> startDartProcess(
Sdk sdk,
List<String> arguments, {
String? cwd,
}) {
log.trace('${sdk.dart} ${arguments.join(' ')}');
print('${sdk.dart} ${arguments.join(' ')}');
print('CWD: $cwd');
return Process.start(sdk.dart, arguments, workingDirectory: cwd);
}
我加了两行日志,输出:
/home/maxiee/Code/dart-sdk/sdk/out/ReleaseX64/dart-sdk/bin/dart --snapshot-kind=app-jit --snapshot=/home/maxiee/Code/dart-sdk/sdk/maxiee_learn/main.jit --verbosity=all /home/maxiee/Code/dart-sdk/sdk/maxiee_learn/main.dart
CWD: null
Process.start
是 Dart 语言的启动进程方法,可见在新进程中,运行的还是同一个 dart 命令,但这次传入了不同的参数。
接下来会来到 Dart C++ 部分的实现。
本文作者:Maeiee
本文链接:2.2 Dart compile Dart 部分实现
版权声明:如无特别声明,本文即为原创文章,版权归 Maeiee 所有,未经允许不得转载!
喜欢我文章的朋友请随缘打赏,鼓励我创作更多更好的作品!